﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using log4net;
using System.Reflection;
using Cn.Edwon.Biz;
using System.Collections.Specialized;
using System.Collections;
using NHibernate.Criterion;

namespace Cn.Edwon.Web.Crud {
    public class CrudOperation {
        public static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        public CrudOperation(Page page) {
            _Page = page;
        }
        public CrudOperation() {
            _Page = null;
        }

        #region 公共属性定义
        private ModelEO _Model;
        public ModelEO Model {
            get { return _Model; }
        }
        #endregion

        #region 私有属性定义
        /// <summary>
        /// 当前操作的动作类型
        /// </summary>
        private CrudActionType _Action;
        public CrudActionType Action { get { return _Action; } }
        /// <summary>
        /// 当前页面
        /// </summary>
        private Page _Page;
        private IBiz _Biz;
        private Object _Instance;

        private IList<Object> _List;
        public IList<Object> DataList {
            set { _List = value; }
            get { return _List; }
        }
        private Int32 _PageIndex;
        public Int32 PageIndex { get { return _PageIndex; } }
        private Int32 _TotalSize;
        public Int32 TotalSize { get { return _TotalSize; } }
        private String _Url;
        public String Url { get { return _Url; } }

        private IList<Order> _Orders;
        
        #endregion

        #region 程序入口
        public void Process(String id,IBiz rBiz) {
            if (_Page == null) {
                log.Error("当前页的Page对象为空");
                return;
            }
            try {
                if (String.IsNullOrEmpty(id)) {
                    _Model = ContextHelper.Parse(_Page.Request.Url);
                } else {
                    _Model = ContextHelper.Parse(id);
                }
                if (_Model == null) {
                    //_Page.ClientScript.RegisterClientScriptBlock(_Page.GetType(), "crud_error", "var CRUD_ERROR=\"Model Undefined\";",true);
                    return;
                }
            } catch(Exception ex) {
                log.Error("装载model数据时错误",ex);
                _Page.ClientScript.RegisterClientScriptBlock(_Page.GetType(), "crud_error", "var CRUD_ERROR=\"" + ex.Message.Replace("\"", "\\\"") + "\";",true);
                return;
            }
            //判断rBiz是否实现了IBiz接口
            _Biz = rBiz;
            if (_Page.IsPostBack) {
                InitOnPostPack();
                switch (_Action) {
                    case CrudActionType.Create:
                        //执行创建的动作
                        this.OnCreate();
                        BindModelData();
                        break;
                    case CrudActionType.Delete:
                        //执行删除动作
                        this.OnDelete();
                        break;
                    case CrudActionType.Update:
                        //执行更新动作
                        this.OnUpdate();
                        BindModelData();
                        break;
                    case CrudActionType.Read:
                        this.OnRead();
                        BindModelData();
                        break;
                    case CrudActionType.Search:
                    case CrudActionType.Select:
                    default:
                        //搜索
                        this.OnSearch();
                        break;
                }
            } else {
                InitOnLoad();
                switch (_Action) {
                    case CrudActionType.Update:
                        BindModelData();
                        break;
                    case CrudActionType.Read:
                        BindModelData();
                        break;
                    case CrudActionType.Create:
                    case CrudActionType.Delete:
                        break;
                    case CrudActionType.Search:
                    case CrudActionType.Select:
                    default:
                        LoadListData();
                        break;
                }
            }
            BuildModelDataCode();
        }
        public void Process(IBiz rBiz) {
            Process(null, rBiz);
        }
        #endregion

        #region 初始化工作
        /// <summary>
        /// 初始化当前的操作动作
        /// </summary>
        /// <param name="value"></param>
        private void InitOnLoad() {
            Init();
            try {
                _Action = (CrudActionType)Enum.Parse(typeof(CrudActionType), _Page.Request.QueryString["crud"]);
            } catch {
                _Action = CrudActionType.Select;
            }
            _Model.ModelId = _Page.Request.QueryString["model"];
        }
        private void InitOnPostPack() {
            Init();
            try {
                _Action = (CrudActionType)Enum.Parse(typeof(CrudActionType), _Page.Request.Form["_CRUD_ACTION"]);
            } catch {
                _Action = CrudActionType.Select;
            }
            _Model.ModelId = _Page.Request.Form["_CRUD_Model_ID"];
        }
        private void Init() {
            //url
            InitUrl();
            //page
            _PageIndex = 1;
            try {
                if (_Page.Request.QueryString["page"] != null) {
                    _PageIndex = Convert.ToInt32(_Page.Request.QueryString["page"]);
                } else if (_Page.Request.Form["page"] != null) {
                    _PageIndex = Convert.ToInt32(_Page.Request.Form["page"]);
                }
            } catch { }
            BindOrder();
        }
        private void InitUrl() {
            _Url = _Page.Request.Url.ToString();
            NameValueCollection urlQuery = _Page.Request.QueryString;
            String[] keys = urlQuery.AllKeys;
            String newQuery = "";
            Boolean first = true;
            for (int i = 0; i < keys.Length; i++) {
                if (keys[i].ToLower() == "crud" || keys[i].ToLower() == "model" || keys[i].ToLower() == "page") continue;
                if (first) {
                    newQuery += "?";
                    first = false;
                } else {
                    newQuery += "&";
                }
                newQuery += keys[i] + "=" + urlQuery[keys[i]];
            }
            if (_Url.IndexOf("?") != -1) {
                _Url = _Url.Substring(0, _Url.IndexOf("?"));
            }
            _Url += newQuery;
        }
        #endregion

        #region 其他私有方法
        private void LoadListData() {
            IList<ICriterion> crits = null;
            try {
                crits = BindSearchPost();
            } catch (Exception ex) {
                log.Error("绑定查询条件数据时错误", ex);
                crits = null;
            }
            if (crits == null || crits.Count < 1) {
                _List = _Biz.Load(_Model.Type, _Model.Pk, _PageIndex, _Model.PageSize, null, _Orders);
            } else {
                _List = _Biz.Load(_Model.Type, _Model.Pk, _PageIndex, _Model.PageSize, crits, _Orders);
            }
        }
        private Boolean IsStringValue(Object value) {
            Type t = value.GetType();
            return ( t.Equals(typeof(String))
                || t.Equals(typeof(DateTime))
                );
        }
        private String StrFilter(String v) {
            if (String.IsNullOrEmpty(v)) {
                return v;
            } else {
                return v.Replace("\"", "\\\"");
            }
        }
        private Object BindFromPost(Object instance) {
            PropertyInfo[] pis = _Model.Type.GetProperties();
            String strVal = "";
            foreach (PropertyInfo pi in pis) {
                if (pi.Name.Equals(_Model.Pk)) continue;
                strVal = _Page.Request.Form[_Model.Type.Name + "_" + pi.Name];
                if (strVal==null) continue;
                Object val = null;
                if (pi.PropertyType.FullName.IndexOf("System") == -1) {
                    //找到该属性在model中的定义
                    foreach (PropertyEO p in _Model.Properties) {
                        if (p.Name == pi.Name) {
                            val = Activator.CreateInstance(pi.PropertyType);
                            PropertyInfo _pi = pi.PropertyType.GetProperty(p.DataSource.ValColumn);
                            _pi.SetValue(val, strVal,null);
                            break;
                        }
                    }
                } else if (pi.PropertyType.Equals(typeof(Boolean))) {
                    val = (strVal == "1" || strVal.ToLower() == "true" || strVal.ToLower() == "yes");
                } else if (pi.PropertyType.Equals(typeof(DateTime))) {
                    val = DateTime.Parse(strVal);
                } else {
                    val = Convert.ChangeType(strVal,pi.PropertyType);
                }
                pi.SetValue(instance, val, null);
            }
            return instance;
        }
        private IList<ICriterion> BindSearchPost() {
            IList<ICriterion> crits = new List<ICriterion>();
            foreach (PropertyEO p in _Model.Properties) {
                if (!p.InSearch) continue;
                PropertyInfo pi = _Model.Type.GetProperty(p.Name);
                String strVal = _Page.Request.Form[_Model.Type.Name + "_" + pi.Name];
                if (!String.IsNullOrEmpty(strVal)) {
                    p.Value = Convert.ChangeType(strVal, pi.PropertyType);
                    crits.Add(Expression.Like(p.Name, "%"+p.Value+"%"));
                }
            }
            return crits;
        }
        private void BindOrder() {
            _Orders = new List<Order>();
            if (_Model != null) return;
            foreach (PropertyEO p in _Model.Properties) { 
                if(String.IsNullOrEmpty(p.Order))continue;
                Boolean ascending = (!p.Order.ToLower().Equals("desc"));
                Order order = new Order(p.Name, ascending);
                _Orders.Add(order);
            }
        }
        #endregion

        #region 构造页面代码
        private void BindModelData() {
            if (_Instance == null) {
                if (String.IsNullOrEmpty(_Model.ModelId)) return;
                _Instance = Activator.CreateInstance(_Model.Type);
                _Biz.Load(_Instance, _Model.ModelId);
            }
            foreach (PropertyEO p in _Model.Properties) {
                PropertyInfo pi = _Model.Type.GetProperty(p.Name);
                if(pi==null)continue;
                Object val = pi.GetValue(_Instance,null);
                if (p.Type.Name.IndexOf("System.") != 0 && p.DataSource != null) {
                    PropertyInfo _pi = val.GetType().GetProperty(p.DataSource.ValColumn);
                    if(_pi!=null)
                        p.Value = _pi.GetValue(val,null);
                } else {
                    p.Value = val;
                }
            }
        }
        private String GenerateFormCode() {
            StringBuilder sbf = new StringBuilder();
            sbf.Append(",\"Form\":[");
            Boolean nofirst = false;
            foreach (PropertyEO eo in _Model.Properties) {
                if (nofirst) {
                    sbf.Append(",");
                } else {
                    nofirst = true;
                }
                sbf.Append("{");
                sbf.Append("\"Name\":\"" + eo.Name + "\"");
                sbf.Append(",\"Label\":\"" + StrFilter(eo.Label) + "\"");
                sbf.Append(",\"DataType\":\"" + StrFilter(eo.DataType) + "\"");
                sbf.Append(",\"Length\":" + eo.Length);
                sbf.Append(",\"Editable\":" + eo.Editable.ToString().ToLower());
                sbf.Append(",\"InForm\":" + eo.InForm.ToString().ToLower());
                sbf.Append(",\"InList\":" + eo.InList.ToString().ToLower());
                sbf.Append(",\"NotNull\":" + eo.NotNull.ToString().ToLower());
                sbf.Append(",\"Unique\":" + eo.Unique.ToString().ToLower());
                if (eo.Value != null) {
                    if(eo.Value.GetType().Equals(typeof(Boolean))){
                        sbf.Append(",\"Value\":" + eo.Value.ToString().ToLower());
                    } else if (IsStringValue(eo.Value)) {
                        sbf.Append(",\"Value\":\"" + StrFilter(eo.Value.ToString()) + "\"");
                    } else{
                        sbf.Append(",\"Value\":" + eo.Value.ToString());
                    }
                } else {
                    sbf.Append(",\"Value\":\"\"");
                }
                sbf.Append(",\"InSearch\":" + eo.InSearch.ToString().ToLower() + "");
                sbf.Append(",\"DataSrc\":\"" + StrFilter(eo.DataSrc) + "\"");
                if (String.IsNullOrEmpty(eo.HtmlCode)) {
                    sbf.Append(",\"HtmlCode\":\"" + StrFilter(eo.HtmlCode) + "\"");
                } else {
                    sbf.Append(",\"HtmlCode\":null");
                }
                sbf.Append("}");
            }
            sbf.Append("]");
            return sbf.ToString();
        }
        private String GenerateDataSourceCode() {
            StringBuilder sb = new StringBuilder();
            sb.Append(",\"DataSource\":{");
            Boolean nofirstp = false;
            foreach (PropertyEO p in _Model.Properties) {
                if (p.DataSource==null) continue;
                DataSourceEO ds = p.DataSource;
                IList<Object> list = _Biz.LoadAll(ds.DataType);
                PropertyInfo pi;
                if (nofirstp) {
                    sb.Append(",");
                } else {
                    nofirstp = true;
                }
                sb.Append("\""+p.Name+"\":[");
                Boolean nofirst = false;
                foreach (Object obj in list) {
                    if (nofirst) {
                        sb.Append(",");
                    } else {
                        nofirst = true;
                    }
                    pi = ds.DataType.GetProperty(ds.ValColumn);
                    if (pi == null) {
                        log.Error("DataSource指定的EO不具有" + ds.ValColumn + "属性1");
                        return "";
                    }
                    sb.Append("[\"" + pi.GetValue(obj, null).ToString() + "\"");
                    pi = ds.DataType.GetProperty(ds.TxtColumn);
                    if (pi == null) {
                        log.Error("DataSource指定的EO不具有" + ds.TxtColumn + "属性2");
                        return "";
                    }
                    sb.Append(",\"" + pi.GetValue(obj, null).ToString() + "\"]");
                }
                sb.Append("]");
            }
            sb.Append("}");
            return sb.ToString();
        }
        private String GenerateViewHeaderCode() {
            StringBuilder sbh = new StringBuilder();
            sbh.Append(",\"Header\":[");
            Boolean nofirst = false;
            foreach (PropertyEO p in _Model.Properties) {
                if (!p.InList) continue;
                PropertyInfo pi = _Model.Type.GetType().GetProperty(p.Name);
                if (nofirst) {
                    sbh.Append(",");
                } else {
                    nofirst = true;
                }
                sbh.Append("\"" + p.Name + "," + p.Label + ","+p.DataType+"\"");
            }
            sbh.Append("]");
            return sbh.ToString();
        }
        private String GenerateViewCode() {
            StringBuilder sbv = new StringBuilder();
            sbv.Append(",\"List\":[");
            //遍历查询数据集的行
            _TotalSize = (Int32)_List[0];
            for (int i = 1; i < _List.Count(); i++) {
                PropertyInfo[] pis = _List[i].GetType().GetProperties();
                if (i == 1) {
                    sbv.Append("[");
                } else {
                    sbv.Append(",[");
                }
                //遍历每行数据集的字段
                PropertyInfo pipk = _Model.Type.GetProperty(_Model.Pk);
                sbv.Append("\"" + pipk.GetValue(_List[i], null) + "\"");
                foreach (PropertyEO p in _Model.Properties) {
                    if (!p.InList) continue;
                    PropertyInfo pi = _Model.Type.GetProperty(p.Name);
                    if (pi != null)
                        sbv.Append(",\"" + pi.GetValue(_List[i], null) + "\"");
                    else
                        sbv.Append(",\"\"");
                }
                sbv.Append("]");
            }
            sbv.Append("]");
            return sbv.ToString();
        }
        private String GeneratePageCode() {
            StringBuilder sb = new StringBuilder();
            sb.Append(",\"PageSize\":"+_Model.PageSize);
            sb.Append(",\"Page\":"+_PageIndex);
            sb.Append(",\"TotalSize\":" + _TotalSize);
            return sb.ToString() ;
        }
        private String GenerateSearchCode() {
            StringBuilder sb = new StringBuilder();
            sb.Append(",\"Search\":[");
            Boolean first = true;
            foreach (PropertyEO p in _Model.Properties) {
                if (!p.InSearch) continue;
                if (first) {
                    first = false;
                } else {
                    sb.Append(",");
                }
                sb.Append("{");
                sb.Append("\"Name\":\""+p.Name+"\"");
                sb.Append(",\"Type\":\"" + p.DataType + "\"");
                sb.Append(",\"Label\":\"" + p.Label + "\"");
                sb.Append(",\"DataSrc\":\"" + p.DataSrc + "\"");
                sb.Append(",\"Value\":\"" + p.Value + "\"");
                sb.Append("}");
            }
            sb.Append("]");
            return sb.ToString();
        }
        private void BuildModelDataCode() {
            StringBuilder sb = new StringBuilder();
            sb.Append("var CRUD={");
            sb.Append("\"Model\":{");
            sb.Append("\"ID\":\"" + _Model.ModelId + "\"");
            sb.Append(",\"Type\":\"" + _Model.Type.Name + "\"");
            sb.Append(",\"Create\":" + _Model.HasCreate.ToString().ToLower() + "");
            sb.Append(",\"Delete\":" + _Model.HasDelete.ToString().ToLower() + "");
            sb.Append(",\"Read\":" + _Model.HasRead.ToString().ToLower() + "");
            sb.Append(",\"Update\":" + _Model.HasUpdate.ToString().ToLower() + "");
            sb.Append("}");
            sb.Append(",\"Url\":\"" + _Url + "\"");
            sb.Append(",\"Action\":\"" + ((int)_Action) + "\"");
            //form 数据
            if (_Action == CrudActionType.Create
                || _Action == CrudActionType.Read
                || _Action == CrudActionType.Update) {
                sb.Append(GenerateFormCode());
                sb.Append(GenerateDataSourceCode());
            }
            //gridview数据
            if (_Action == CrudActionType.Select
                || _Action == CrudActionType.Search) {
                sb.Append(GenerateViewHeaderCode());
                sb.Append(GenerateViewCode());
                sb.Append(GeneratePageCode());
                sb.Append(GenerateSearchCode());
            }
            sb.Append("};");
            _Page.ClientScript.RegisterClientScriptBlock(_Page.GetType(), _Model.ModelId, sb.ToString(), true);
        }
        
        #endregion

        #region 事件处理程序

        #region load事件组
        #region 事件：处理Create页面装载前
        public event EventHandler CreateLoad;
        public void OnCreateLoad() {
            if (this.CreateLoad != null) {
                this.CreateLoad(this, new EventArgs());
            }
        }
        public void DoCreateLoad(object sender, EventArgs e) {
        }
        #endregion

        #region 事件：处理Update页面装载前
        public event EventHandler UpdateLoad;
        public void OnUpdateLoad() {
            if (this.UpdateLoad != null) {
                this.UpdateLoad(this, new EventArgs());
            }
        }
        public void DoUpdateLoad(object sender, EventArgs e) {
        }
        #endregion

        #region 事件：处理read页面装载前
        public event EventHandler ReadLoad;
        public void OnReadLoad() {
            if (this.ReadLoad != null) {
                this.ReadLoad(this, new EventArgs());
            }
        }
        public void DoReadLoad(object sender, EventArgs e) {
        }
        #endregion

        #region 事件：处理select页面装载前
        public event EventHandler ListLoad;
        public void OnListLoad() {
            if (this.ListLoad != null) {
                this.ListLoad(this, new EventArgs());
            }
        }
        public void DoListLoad(object sender, EventArgs e) {
        }
        #endregion
        #endregion

        #region 提交事件组
        #region 事件：处理搜索事件
        public event EventHandler Search;
        public void OnSearch() {
            if (this.Search != null) {
                this.Search(this, new EventArgs());
            }
        }
        public void DoSearch(object sender, EventArgs e) {
            LoadListData();
        }
        #endregion

        #region 处理Read事件
        public event EventHandler Read;
        public void OnRead() {
            if (this.Read != null) {
                this.Read(this, new EventArgs());
            }
        }
        public void DoRead(object sender, EventArgs e) {
            return;
        }
        #endregion

        #region 处理Create事件
        public event EventHandler Create;
        public void OnCreate() {
            if (this.Create != null) {
                this.Create(this, new EventArgs());
            }
        }
        public void DoCreate(object sender, EventArgs e) {
            _Instance = Activator.CreateInstance(_Model.Type);
            try {
                _Instance = BindFromPost(_Instance);
                _Biz.Save(_Model.Type.Name, _Instance);
                SiteInfo.SendSucceed(_Page, _Url);
            } catch (Exception ex) {
                SiteInfo.Send(_Page, "操作失败", ex.Message);
            }
        }
        #endregion

        #region 处理Update事件
        public event EventHandler Update;
        public void OnUpdate() {
            if (this.Update != null) {
                this.Update(this, new EventArgs());
            }
        }
        public void DoUpdate(object sender, EventArgs e) {
            if (String.IsNullOrEmpty(_Model.ModelId)) {
                SiteInfo.Send(_Page, "操作失败", "主键参数丢失");
                return;
            }
            _Instance = Activator.CreateInstance(_Model.Type);
            try {
                _Biz.Load(_Instance, _Model.ModelId);
                _Instance = BindFromPost(_Instance);
                _Biz.Update(_Model.Type.Name, _Instance);
                SiteInfo.SendSucceed(_Page, _Url);
            } catch (Exception ex) {
                SiteInfo.Send(_Page, "操作失败", ex.Message);
            }
        }
        #endregion

        #region 处理删除事件
        public event EventHandler Delete;
        public void OnDelete() {
            if (this.Delete != null) {
                this.Delete(this, new EventArgs());
            }
        }
        public void DoDelete(object sender, EventArgs e) {
            IList keys = new ArrayList();
            String keyStr = _Page.Request.Form["_CRUD_GridView_CheckBox"];
            if (!String.IsNullOrEmpty(keyStr)) {
                String[] keyArr = keyStr.Split(',');
                for (int i = 0; i < keyArr.Length; i++)
                    keys.Add(keyArr[i]);
            }
            try {
                _Biz.Delete(_Model.Type, keys);
                SiteInfo.SendSucceed(_Page, _Url);
            } catch(Exception ex) {
                SiteInfo.Send(_Page,"操作失败",ex.Message);
            }
        }
        #endregion
        #endregion

        #endregion
    }
}
